/*
 * Copyright [yyyy] [name of copyright owner]
 * Licensed under the Apache License, Version 2.0 (the "License");
 * You may obtain a copy of the License at

 * http://www.apache.org/licenses/LICENSE-2.0

 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.github.akashohos90.imageletter.drawable;

import ohos.agp.colors.RgbColor;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.render.Canvas;
import ohos.agp.render.PixelMapHolder;
import ohos.agp.utils.Color;
import ohos.agp.utils.Rect;
import ohos.agp.utils.RectFloat;
import ohos.media.image.PixelMap;

/**
 * Image Drawable
 *
 * @since 2021-05-27
 */
public class RoundedDrawable extends ShapeElement {
    private static final float SHADE_FACTOR = 0.9f;

    private static final int VALUE_TWO = 2;

    private static final int VALUE_DEFAULT = -1;

    private final PixelMap mPixelMap;

    private final int mShape;

    private final int mHeight;

    private final int mWidth;

    private final float mRadius;

    private final int mBorderThickness;

    private final int mBorderColor;

    private RoundedDrawable(Builder builder) {
        super();

        // shape properties
        mShape = builder.builderShape;
        mHeight = builder.builderHeight;
        mWidth = builder.builderWidth;
        mRadius = builder.builderRadius;

        // text and drawable color
        mPixelMap = builder.builderPixelMap;

        // border settings
        mBorderThickness = builder.builderBorderThickness;
        mBorderColor = builder.builderBorderColor;
    }

    private int getDarkerShade(int color) {
        RgbColor rgb = RgbColor.fromArgbInt(color);
        return Color.rgb((int) (SHADE_FACTOR * rgb.getRed()),
                (int) (SHADE_FACTOR * rgb.getGreen()),
                (int) (SHADE_FACTOR * rgb.getBlue()));
    }

    @Override
    public void drawToCanvas(Canvas canvas) {
        Rect rect = getBounds();
        int tempWidth = this.mWidth < 0 ? rect.getWidth() : this.mWidth;
        int tempHeight = this.mHeight < 0 ? rect.getHeight() : this.mHeight;
        float radiusX = this.mRadius < 0 ? (float) tempWidth / VALUE_TWO : this.mRadius;
        float radiusY = this.mRadius < 0 ? (float) tempHeight / VALUE_TWO : this.mRadius;
        RectFloat rectDst = new RectFloat(0, 0, tempWidth, tempHeight);
        RectFloat rectSrc = new RectFloat(0, 0,
                mPixelMap.getImageInfo().size.width, mPixelMap.getImageInfo().size.height);
        PixelMapHolder pixelMapHolder = new PixelMapHolder(mPixelMap);
        canvas.drawPixelMapHolderRoundRectShape(pixelMapHolder, rectSrc, rectDst, radiusX, radiusY);
        setShape(mShape);
        setCornerRadius(mRadius);
        setStroke(mBorderThickness, RgbColor.fromArgbInt(getDarkerShade(Color.BLACK.getValue())));
        super.drawToCanvas(canvas);
    }

    /**
     * builder
     *
     * @return IShapeBuilder
     */
    public static IShapeBuilder builder() {
        return new Builder();
    }

    /**
     * Builder
     *
     * @since 2021-05-27
     */
    public static class Builder implements IConfigBuilder, IShapeBuilder, IBuilder {
        private PixelMap builderPixelMap;

        private int builderBorderThickness;

        private int builderBorderColor;

        private int builderWidth;

        private int builderHeight;

        private int builderShape;

        private float builderRadius;

        private Builder() {
            builderBorderThickness = 0;
            builderBorderColor = Color.BLACK.getValue();
            builderWidth = VALUE_DEFAULT;
            builderHeight = VALUE_DEFAULT;
            builderRadius = VALUE_DEFAULT;
            builderShape = ShapeElement.RECTANGLE;
        }

        /**
         * width
         *
         * @param width width
         * @return IConfigBuilder
         */
        public IConfigBuilder width(int width) {
            this.builderWidth = width;
            return this;
        }

        /**
         * height
         *
         * @param height height
         * @return IConfigBuilder
         */
        public IConfigBuilder height(int height) {
            this.builderHeight = height;
            return this;
        }

        /**
         * withBorder
         *
         * @param thickness thickness
         * @return IConfigBuilder
         */
        public IConfigBuilder withBorder(int thickness) {
            this.builderBorderThickness = thickness;
            return this;
        }

        /**
         * withBorderColor
         *
         * @param borderColor color
         * @return IConfigBuilder
         */
        public IConfigBuilder withBorderColor(int borderColor) {
            this.builderBorderColor = borderColor;
            return this;
        }

        @Override
        public IConfigBuilder beginConfig() {
            return this;
        }

        @Override
        public IShapeBuilder endConfig() {
            return this;
        }

        @Override
        public IBuilder rect() {
            this.builderShape = ShapeElement.RECTANGLE;
            return this;
        }

        @Override
        public IBuilder round() {
            this.builderShape = ShapeElement.OVAL;
            return this;
        }

        @Override
        public IBuilder roundRect(int radius) {
            this.builderRadius = radius;
            this.builderShape = ShapeElement.RECTANGLE;

            return this;
        }

        @Override
        public RoundedDrawable buildRect(PixelMap pixelMap) {
            rect();
            return build(pixelMap);
        }

        @Override
        public RoundedDrawable buildRoundRect(PixelMap pixelMap, int radius) {
            roundRect(radius);
            return build(pixelMap);
        }

        @Override
        public RoundedDrawable buildRound(PixelMap pixelMap) {
            round();
            return build(pixelMap);
        }

        @Override
        public RoundedDrawable build(PixelMap pixelMap) {
            this.builderPixelMap = pixelMap;
            return new RoundedDrawable(this);
        }
    }

    /**
     * IConfigBuilder Interface
     *
     * @since 2021-05-27
     */
    public interface IConfigBuilder {
        /**
         * width
         *
         * @param width width
         * @return IConfigBuilder
         */
        IConfigBuilder width(int width);

        /**
         * height
         *
         * @param height height
         * @return IConfigBuilder
         */
        IConfigBuilder height(int height);

        /**
         * withBorder
         *
         * @param thickness thickness
         * @return IConfigBuilder
         */
        IConfigBuilder withBorder(int thickness);

        /**
         * withBorderColor
         *
         * @param color color
         * @return IConfigBuilder
         */
        IConfigBuilder withBorderColor(int color);

        /**
         * endConfig
         *
         * @return IShapeBuilder
         */
        IShapeBuilder endConfig();
    }

    /**
     * IBuilder Interface
     *
     * @since 2021-05-27
     */
    public interface IBuilder {
        /**
         * build
         *
         * @param pixelMap pixelMap
         * @return RoundedDrawable
         */
        RoundedDrawable build(PixelMap pixelMap);
    }

    /**
     * IShapeBuilder Interface
     *
     * @since 2021-05-27
     */
    public interface IShapeBuilder {
        /**
         * beginConfig
         *
         * @return IConfigBuilder
         */
        IConfigBuilder beginConfig();

        /**
         * rect
         *
         * @return IBuilder
         */
        IBuilder rect();

        /**
         * round
         *
         * @return IBuilder
         */
        IBuilder round();

        /**
         * roundRect
         *
         * @param radius radius
         * @return IBuilder
         */
        IBuilder roundRect(int radius);

        /**
         * buildRect
         *
         * @param pixelMap pixelMap
         * @return RoundedDrawable
         */
        RoundedDrawable buildRect(PixelMap pixelMap);

        /**
         * buildRoundRect
         *
         * @param pixelMap pixelMap
         * @param radius radius
         * @return RoundedDrawable
         */
        RoundedDrawable buildRoundRect(PixelMap pixelMap, int radius);

        /**
         * buildRound
         *
         * @param pixelMap pixelMap
         * @return RoundedDrawable
         */
        RoundedDrawable buildRound(PixelMap pixelMap);
    }
}
